/** @jsxImportSource @emotion/react */
import {jsx,css} from "@emotion/react";
import * as React from "react";
import {CSSProperties} from "react";
import {
    useGestureResponder,
    StateType,
    Callbacks,
    ResponderEvent
} from "react-gesture-responder";
import { useSprings, animated } from '@react-spring/web';
//类型问题
// @ts-ignore
import {useDrag, useGesture} from '@use-gesture/react';
// import clamp from 'lodash.clamp'
// import { useMeasure } from "./Hooks/use-measure";
// import { usePrevious } from "./Hooks/previous";
// import {useScrollLock} from "./Hooks/use-scroll-lock";
import {  usePrevious,
    useTheme, Text, LayerRefComp,Touchable,
} from "customize-easy-ui-component";
import {useMeasure} from "customize-easy-ui-component/esm/Hooks/use-measure";
import {useScrollLock} from "customize-easy-ui-component/esm/Hooks/use-scroll-lock";
import {Vector2} from "@use-gesture/core/dist/declarations/src/types/utils";



//很容易触发框架层的拉动！？



/**
 * ReactPager
 * Provide views that can be swiped left or right (with touch devices).
 * 旧的有interface PagerProps extends React.HTMLAttributes<HTMLDivElement> ； children类型冲突；
 */
export interface PagerProps  {
    id?: string | undefined;
    //代表是当前显示哪一个儿子; onRequestChange配合执行，上级组件决定最终 value：index 该显示的儿子序号。
    value: number;
    //回调触发：切换到哪一个儿子去了
    //【注意】onRequestChange 必须把 value 参数值进行修改，否则无法真的切换。支持 异步的 懒惰加载组件数据。
    onRequestChange: (value: number) => void;

    //允许很长儿子队列只需要加载一部分儿子。
    lazyLoad?: boolean;      //懒加载总开关: 允许某些儿子mount实际时间滞后。
    //允许部分加载机制： 依据suggestedIndex来回调设置应当同时给与加载的那些兄弟，不是都是拖延加载的做法;
    onSetLazy?: (suggestedIndex: number) => number[];
    /* 拉不动了： 转交给上一级的轮播台机会拉动 ；
       beyondX 拉拽X方向已经超限制了：=-1 表示X轴左边超出  =1 表示X轴右边超出。  beyondY 高度方向的超出。
    * */
    onNestDragEnd?: (direction: Vector2) => boolean;

    //不能使用这样 paneStyle?: SerializedStyles;定义； 没法注入 style:{};
    paneStyle?: CSSProperties | undefined;

    children: Array<React.ReactNode>;
    //children: Array<React.ReactNode | CallbackProps>;
    //style: 隐藏 在HTMLAttributes里面
    style?: CSSProperties | undefined;
    //要不要允许手势操作处理，允许拉拽？
    noBind?: boolean;
}


//向上级组件暴露的操作接口
export interface PagerHandles {
    focus(i?: number): void;
}

export interface CallbackProps {
    style: React.CSSProperties;
    "aria-hidden": boolean;
    ref: (el: HTMLDivElement | null) => void;
}

//也允许搞函数式儿子：     if (typeof child === "function")
export type PagerChildCallback = (
    props: CallbackProps,
    active: boolean,
    load: boolean
) => React.ReactNode;

// const pages = [
//     'https://images.pexels.com/photos/62689/pexels-photo-62689.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260',
//     'https://images.pexels.com/photos/733853/pexels-photo-733853.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260',
//     'https://images.pexels.com/photos/4016596/pexels-photo-4016596.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260',
//     'https://images.pexels.com/photos/351265/pexels-photo-351265.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260',
//     'https://images.pexels.com/photos/924675/pexels-photo-924675.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260',
// ]


export const Gesture4Page  = React.forwardRef(
    (
        {
            children,
            id,
            value: index,
            onRequestChange,
            lazyLoad = false,
            onSetLazy,
            onNestDragEnd,
            style,
            paneStyle,
            noBind=false,
            ...other
        } : PagerProps,
        ref
  ) =>  {
        //  const index = useRef(0)
        const indexRef = React.useRef(index)
        console.log("render页面旭:",indexRef.current, index);
        const containerRef = React.useRef(null);      //绑定 拉拽的第一层Div;
        const { bounds } = useMeasure(containerRef);
        const { width } = bounds

        const [isDragging, setIsDragging] = React.useState(false);
    //已经加载的部分： 多个儿子，不一定都加载mount完毕; 轮播切换不会卸载。 [index]默认只能加载一个;
    const [loaded, setLoaded] = React.useState(
        () => new Set(onSetLazy ? onSetLazy(index) : [index])
    );


    //当前已经加载的儿子映射DOM;
    const childrenRefs = React.useRef<Map<number, HTMLDivElement | null>>(
        new Map()
    );
    //上一次位置
    const previousIndex = usePrevious(index);
    //当前应该轮播位置
    const shouldFocusRef = React.useRef<number | null>(index || null);

     // useScrollLock(isDragging);        //&& enableScrollLock

    React.useEffect(() => {
        if (typeof previousIndex === "number" && previousIndex !== index) {
            shouldFocusRef.current = index;
        } else {
            shouldFocusRef.current = null;
        }
    }, [previousIndex, index]);
 //直接定位滚到某个儿子吗？
    function focusByIndex(i: number) {
        const el = childrenRefs.current.get(i);
        if (el) {
            el.focus();
        }
    }

    // expose an imperative focus function which focuses the currently active index
    //上级组件可能使用本接口直接操作 focusByIndex切换到某一个儿子， 跳过轮播滑动:也是可能切换轮播台的。
    React.useImperativeHandle(ref, () => ({
        focus: (i?: number) => {
            focusByIndex(i || index);
        }
    }));

    const renderableChildren = children.filter(child => child !== null);

    // gesture view counts
    const childCount = renderableChildren.length;
    const maxIndex = childCount - 1;      //最大儿子的序号。
    const minIndex = 0;     //固定的


    /**
     * Prevent invalid indexes
     */

    function isValidNextIndex(index: number) {
        return index >= minIndex  && index <= maxIndex;
    }

    /** 跟踪设置应该加载的儿子;
     * We keep a set of indexes that should
     * be loaded for lazy loading.
     * @param index:, 应该加载的儿子
     */
    function addIndexToLoaded(index: number) {
        if (!isValidNextIndex(index)) {
            return;
        }

        let indexes: number | number[] = index;

        // allow the user to customize which indexes to load
        if (onSetLazy) {
            indexes = onSetLazy(index);
        }

        const indexesArray = Array.isArray(indexes) ? indexes : [indexes];
        const next = new Set(loaded);
        //重新洗牌 next= 旧的已经加载儿子们；
        indexesArray.forEach(i => {
            // don't set items which are already loaded or are invalid
            if (loaded.has(i) || !isValidNextIndex(index)) {
                return;
            }

            next.add(i);
        });

        setLoaded(next);
    }

        const [props, api] = useSprings(childCount, i => ({
            x: i * width,
            scale: 1,
            display: 'block',
        }))

        //初始化时刻width==0影响大。 儿子div显示位置属性也会影响到了拉拽结果。
        React.useEffect(() => {
            loaded.add(index);
            indexRef.current=index;
            api.start(i => {
                if (i < indexRef.current - 1 || i > indexRef.current + 1)
                    return { display: 'none' }
                const x = (i - indexRef.current) * width ;
                const scale =  1;
                return { x, scale, display: 'block' }
            })
        }, [index, width,api,loaded]);


        function doDrag(state : any) {
            const { active, movement: [mx], direction: [xDir] , cancel, event, swipe:[swpx,swpy],tap,
                last,  velocity: [vx, vy], canceled, axis,} = state;
            console.log("拉动D",state,"active",active,"号序",indexRef.current,"canceled:",canceled,"快滑",swpx);
            event.stopPropagation();
            if(axis!=='x')   cancel();
            api.start(i => {
                if (i < indexRef.current - 1 || i > indexRef.current + 1) return { display: 'none' }
                const x = (i - indexRef.current) * width + (active ? mx : 0)
                const scale = active ? 1 - Math.abs(mx) / width / 2 : 1
                return { x, scale, display: 'block' }
            })
        }
        function doDragStart(state : any) {
            const { active, movement: [mx], direction: [xDir] , cancel, event, swipe:[swpx,swpy],tap,
                last,  velocity: [vx, vy], canceled, } = state;
            console.log("拉动Start",state,"active",active,"号序",indexRef.current,"canceled:",canceled,"快滑",swpx);
            event.stopPropagation();
            api.start(i => {
                if (i < indexRef.current - 1 || i > indexRef.current + 1) return { display: 'none' }
                const x = (i - indexRef.current) * width + (active ? mx : 0)
                const scale = active ? 1 - Math.abs(mx) / width / 2 : 1
                return { x, scale, display: 'block' }
            })
        }
        function doDragEnd(state : any) {
            const { active, movement: [mx,my], direction: [xDir,yDir] , cancel, event, swipe:[swpx,swpy],tap,
                        first,last, velocity: [vx, vy], canceled, axis,} = state;
            console.log("拉动End",state,"active",active,"号序",indexRef.current,"canceled:",canceled,"快滑",swpx);
            //if(!first)  event.stopPropagation();
            //if(axis!=='x')   cancel();   else
            if(!active && last && !canceled && (Math.abs(swpx)>0 || (Math.abs(mx)>=width*0.03 && Math.abs(mx)>Math.abs(my) ) ) ) {
                let Old=indexRef.current;
                // let childCount=pages.length;   //但是#注意有往左拉拽xDir有可能是=0,分开两个孤立事件状态？
                let finalDir= xDir!==0? xDir : mx>0? 1 : -1;
                if(xDir===0  && yDir!==0)   finalDir=0;      //允许水平方向滑动
                if(finalDir!==0){
                    const idxNew= indexRef.current + (finalDir>0 ? -1 : 1);
                    const objIndex= (idxNew > childCount - 1)? (childCount - 1) : idxNew<0? 0 :idxNew;

                    console.log("拉动End Old",Old,"objIndex=",objIndex);
                    if(objIndex===Old){
                        cancel();
                        onNestDragEnd && onNestDragEnd([finalDir,0]);
                    }
                    else {
                        //滑动未到位就该触发懒加载的准备机制。
                        addIndexToLoaded(objIndex);
                        indexRef.current = objIndex;
                        onRequestChange(objIndex);
                        cancel();
                    }
                }
            }
            api.start(i => {
                if (i < indexRef.current - 1 || i > indexRef.current + 1) return { display: 'none' }
                const x = (i - indexRef.current) * width + (active ? mx : 0)
                const scale = active ? 1 - Math.abs(mx) / width / 2 : 1
                return { x, scale, display: 'block' }
            })
        }

        const bind = useGesture(
            {
                // onDrag: (state) => doDrag(state),
                // onDragStart: (state) => doDragStart(state),
                onDragEnd: (state) => doDragEnd(state),
                onPointerMove:  ({ event, ...sharedState }) =>{
                    // console.log('ReaCt合事件发触', event, "sharedState", sharedState);
                    if(event.pointerType!=="mouse")
                            event.stopPropagation();
                },
            },
            {
                drag: {
                    filterTaps: true,
                },
            }
        )

        return (
            <div className="Pager_view"   ref={containerRef}
                 style={{
                     overflow: "hidden",
                     width: "100%",
                     position: "relative",
                     height: "100%",
                 }}
            >
                {props.map(({ x, display, scale }, i) =>{
                        const child= renderableChildren[i];
                      return (
                            <animated.div className="Gesturepanel"
                                          {...bind()}
                                          key={i}
                                          style={{
                                              display,
                                              x ,
                                              width: "100%",
                                              position: "absolute",
                                              height: "100%",
                                              touchAction: 'none',
                                              overflowY: 'auto',
                                          }}
                            >
                                <animated.div style={{
                                    scale,
                                    touchAction: 'none',
                                    // backgroundSize: 'cover',
                                    // backgroundRepeat: `no-repeat`,
                                    // backgroundPosition: `center center`,
                                    width: "100%",
                                    height: "100%",
                                    //boxShadow: `0 62.5px 125px -25px rgba(50, 50, 73, 0.5), 0 37.5px 75px -37.5px rgba(0, 0, 0, 0.6)`,
                                    display: "flex",
                                    flexDirection: "column",
                                    alignSelf: "stretch",
                                    justifyContent: "flex-start",
                                    flexShrink: 0,
                                    overflow: "auto",
                                    outline: "none",
                                    ...paneStyle
                                }} >
                                    { child}
                                </animated.div>
                            </animated.div>
                        )
                    }

                )}
            </div>
        )
}
);


/*更为底层API使用例子 参考@use-gesture/react包文档
       function doDrag(state : any) {
            const { active, movement: [mx], direction: [xDir] , cancel, event, swipe:[swpx,swpy],tap,
                last,  velocity: [vx, vy], canceled, } = state;
            console.log("拉动D",state,"active",active,"号序",indexRef.current,"canceled:",canceled,"快滑",swpx);
            event.stopPropagation();
            api.start(i => {
                if (i < indexRef.current - 1 || i > indexRef.current + 1) return { display: 'none' }
                const x = (i - indexRef.current) * width + (active ? mx : 0)
                const scale = active ? 1 - Math.abs(mx) / width / 2 : 1
                return { x, scale, display: 'block' }
            })
        }
        function doDragStart(state : any) {
            const { active, movement: [mx], direction: [xDir] , cancel, event, swipe:[swpx,swpy],tap,
                last,  velocity: [vx, vy], canceled, } = state;
            api.start(i => {
                if (i < indexRef.current - 1 || i > indexRef.current + 1) return { display: 'none' }
                const x = (i - indexRef.current) * width + (active ? mx : 0)
                const scale = active ? 1 - Math.abs(mx) / width / 2 : 1
                return { x, scale, display: 'block' }
            })
        }
        function doDragEnd(state : any) {
            const { active, movement: [mx], direction: [xDir] , cancel, event, swipe:[swpx,swpy],tap,
                last,  velocity: [vx, vy], canceled, } = state;
            event.stopPropagation();
            if (!active && !canceled && Math.abs(swpx) > 0) {
                let Old=indexRef.current;
                let childCount=pages.length;
                const idxNew= indexRef.current + (swpx > 0 ? -1 : 1);
                const objIndex= (idxNew > childCount - 1)? (childCount - 1) : idxNew<0? 0 :idxNew;
                indexRef.current = objIndex;
                console.log("拉动End Old",Old,"NEW=",indexRef.current);
                cancel()
            }
            api.start(i => {
                if (i < indexRef.current - 1 || i > indexRef.current + 1) return { display: 'none' }
                const x = (i - indexRef.current) * width + (active ? mx : 0)
                const scale = active ? 1 - Math.abs(mx) / width / 2 : 1
                return { x, scale, display: 'block' }
            })
        }
        const bind = useGesture(
            {
                onDrag: (state) => doDrag(state),
                onDragStart: (state) => doDragStart(state),
                onDragEnd: (state) => doDragEnd(state),
            },
           {  }
        )
* */
